package com.zys.http.extension.search.everywhere;

import com.intellij.icons.AllIcons;
import com.intellij.ide.actions.SearchEverywherePsiRenderer;
import com.intellij.ide.actions.searcheverywhere.AbstractGotoSEContributor;
import com.intellij.ide.actions.searcheverywhere.SearchEverywhereContributor;
import com.intellij.ide.actions.searcheverywhere.SearchEverywhereContributorFactory;
import com.intellij.ide.util.gotoByName.FilteringGotoByModel;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.psi.NavigatablePsiElement;
import com.intellij.psi.PsiElement;
import com.intellij.util.TextWithIcon;
import com.zys.http.constant.HttpConstant;
import com.zys.http.entity.tree.MethodNodeData;
import com.zys.http.extension.setting.HttpSetting;
import com.zys.http.processor.ProcessorContext;
import com.zys.http.tool.ThreadTool;
import com.zys.http.ui.tree.node.MethodNode;
import lombok.SneakyThrows;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;

import javax.swing.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

/**
 * @author zys
 * @since 2023-10-10
 */
public class GotoApiSearchEverywhereContributor extends AbstractGotoSEContributor {
    private final GotoApiModel apiModel;

    public GotoApiSearchEverywhereContributor(@NotNull AnActionEvent event) {
        super(event);
        Project project = event.getProject();
        boolean enableSearchEverywhere = HttpSetting.getInstance().getEnableSearchEverywhere();
        GotoApiChooseByNameContributor contributor = new GotoApiChooseByNameContributor(enableSearchEverywhere ? methodNodeDataList(project) : Collections.emptyList());
        this.apiModel = new GotoApiModel(project, contributor);
    }

    private static @NotNull List<MethodNodeData> methodNodeDataList(Project project) {
        Collection<Module> moduleList = ProcessorContext.projectModules(project);
        List<MethodNodeData> methodNodeDataList = new ArrayList<>();
        for (Module m : moduleList) {
            List<? extends PsiElement> controllers = ProcessorContext.moduleControllers(project, m, new ArrayList<>());
            String contextPath = ProcessorContext.modulePath(m, project);
            for (PsiElement controller : controllers) {
                List<MethodNode> methodNodes = ProcessorContext.methodNodes(controller, contextPath);
                List<MethodNodeData> list = methodNodes.stream().map(MethodNode::getValue).toList();
                methodNodeDataList.addAll(list);
            }
        }

        return methodNodeDataList;
    }


    @Override
    public boolean isShownInSeparateTab() {
        return HttpSetting.getInstance().getEnableSearchEverywhere() && !apiModel.getNodeDataList().isEmpty();
    }

    @Override
    public @NotNull String getSearchProviderId() {
        return GotoApiSearchEverywhereContributor.class.getSimpleName();
    }

    @Override
    public @NotNull @Nls String getGroupName() {
        return HttpConstant.PLUGIN_NAME;
    }

    @Override
    public int getSortWeight() {
        return Integer.MAX_VALUE;
    }

    @Override
    protected @NotNull FilteringGotoByModel<?> createModel(@NotNull Project project) {
        return apiModel;
    }

    @Override
    public @NotNull ListCellRenderer<Object> getElementsRenderer() {
        return new SearchEverywherePsiRenderer(this) {
            @Override
            @SneakyThrows
            protected TextWithIcon getItemLocation(Object value) {
                if (value instanceof GotoApiItem item) {
                    return ReadAction.nonBlocking(() -> {
                        NavigatablePsiElement psiElement = item.methodNodeData().getPsiElement();
                        return new TextWithIcon(psiElement.getResolveScope().getDisplayName(), AllIcons.Nodes.Module);
                    }).submit(ThreadTool.getExecutor()).get();
                }
                return super.getItemLocation(value);
            }
        };
    }

    public static class Factory implements SearchEverywhereContributorFactory<Object> {
        @Override
        public @NotNull SearchEverywhereContributor<Object> createContributor(@NotNull AnActionEvent initEvent) {
            return new GotoApiSearchEverywhereContributor(initEvent);
        }
    }
}
